﻿using SuperX.Common;
using SuperX.Common.Abstract;
using SuperX.Common.BasicService;
using SuperX.Common.Collection;
using SuperX.Common.Log;
using SuperX.DataService.Abstract;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;

namespace SuperX.DataService
{
    public class FileDeviceGroup : BaseDeviceGroup, IGroup
    {
        public override bool IsActive { get; set; }

        private void OnUpdate(object stateInfo)
        {
            while (true)
            {
                Thread.Sleep(_updateRate);
                lock (this)
                {
                    if (!_isActive)
                    {
                        return;
                    }
                    Update();
                }
            }
        }

        public void Update()
        {
            DateTime dt = DateTime.Now;
            var list = _fileReader.ReadToList(this.Name);
            if (list != null && list.Any())
            {
                if (DataChange != null)
                {
                    foreach (var fileDatas in list)
                    {
                        foreach (IIOTag tag in _IOTagGroup)
                        {
                            var index = tag.Identity;
                            if (index >= 0)
                            {
                                FileData data = fileDatas.Where(a => a.ID == index).FirstOrDefault();
                                if (tag.Address.VarType == DataType.STR)
                                {
                                    if (data.Text != tag.ToString())
                                    {
                                        (tag as StringTag).Value = data.Text;
                                    }
                                    continue;
                                }
                                else if (tag.Address.VarType == DataType.DYNAMIC)
                                {
                                    (tag as DynamicTag).Value = data.DynamicValue;
                                }
                                else //文件驱动每次都刷新，这里可根据实际使用情况修改
                                {
                                    tag.UpdateTagValue(data.Value);
                                }
                            }
                        }
                        foreach (DataChangeEventHandler deleg in DataChange.GetInvocationList())
                        {
                        }
                    }
                }
                else
                {
                    foreach (IIOTag tag in _IOTagGroup)
                    {
                        foreach (var fileDatas in list)
                        {
                            var index = tag.Identity;
                            if (index >= 0)
                            {
                                FileData data = fileDatas.Where(a => a.ID == index).FirstOrDefault();
                                if (tag.Value != data.Value)
                                {
                                    tag.UpdateTagValue(data.Value);
                                }
                            }
                        }
                    }
                }
            }
        }

        private IFileDriver _fileReader;

        [JsonIgnore]
        public IDriver IDriverParent
        {
            get
            {
                return _fileReader;
            }
        }

        public FileDeviceGroup(string name, int updateRate, bool active, IFileDriver parent)
        {
            this._updateRate = updateRate;
            this._isActive = active;
            this._fileReader = parent;
            this._server = _fileReader.DriverParent;
            this.Name = name;
            this.Parent = parent;
        }

        public bool AddItems(IList<TagConfig> items)
        {
            int count = items.Count;
            lock (_server.SyncRoot)
            {
                int j = 0;
                for (int i = 0; i < count; i++)
                {
                    IIOTag dataItem = null;
                    var meta = items[i];
                    DeviceAddress addr = new DeviceAddress(string.Empty, -1, 0, 0, j++, meta.Size, 0, meta.DataType, meta.Address);
                    switch (meta.DataType)
                    {
                        case DataType.BOOL:
                            dataItem = new BoolTag(addr, this);
                            break;

                        case DataType.BYTE:
                            dataItem = new ByteTag(addr, this);
                            break;

                        case DataType.WORD:
                            dataItem = new UShortTag(addr, this);
                            break;

                        case DataType.SHORT:
                            dataItem = new ShortTag(addr, this);
                            break;

                        case DataType.DWORD:
                            dataItem = new UIntTag(addr, this);
                            break;

                        case DataType.INT:
                            dataItem = new IntTag(addr, this);
                            break;

                        case DataType.FLOAT:
                            dataItem = new FloatTag(addr, this);
                            break;

                        case DataType.STR:
                            dataItem = new StringTag(addr, this);
                            break;

                        case DataType.DYNAMIC:
                            dataItem = new DynamicTag(addr, this);
                            break;

                        default:
                            dataItem = new BoolTag(addr, this);
                            break;
                    }
                    dataItem.Name = meta.Name;
                    dataItem.Interval = meta.Interval;
                    dataItem.Archive = meta.Archive;
                    dataItem.ReadWriteMode = meta.ReadWriteMode;
                    dataItem.Script = meta.Script;
                    dataItem.Maximum = meta.Maximum;
                    dataItem.Minimum = meta.Minimum;
                    dataItem.TagType = meta.TagType;
                    dataItem.Regester = meta.Regester;
                    dataItem.No = meta.No;
                    dataItem.ScaleValue = meta.ScaleValue;
                    dataItem.ConverterType = meta.ConverterType;
                    dataItem.Unit = meta.Unit;
                    dataItem.Description = meta.Description;
                    dataItem.TimeStamp = DateTime.Now;
                    IOTagGroup.Add(dataItem);
                    addr.Name = dataItem.FullName;
                    _server.AddItemIndex(meta.Name, dataItem);
                }
                _items = IOTagGroup.Values;
                _items.TrimExcess();
            }
            return true;
        }

        public bool SetActiveState(bool active, params long[] items)
        {
            return true;
        }

        public ItemData<int> ReadInt32(DeviceAddress address, DataSource source = DataSource.Cache)
        {
            return _fileReader.ReadInt32(address);
        }

        public ItemData<uint> ReadUInt32(DeviceAddress address, DataSource source = DataSource.Cache)
        {
            return _fileReader.ReadUInt32(address);
        }

        public ItemData<ushort> ReadUInt16(DeviceAddress address, DataSource source = DataSource.Cache)
        {
            return _fileReader.ReadUInt16(address);
        }

        public ItemData<short> ReadInt16(DeviceAddress address, DataSource source = DataSource.Cache)
        {
            return _fileReader.ReadInt16(address);
        }

        public ItemData<byte> ReadByte(DeviceAddress address, DataSource source = DataSource.Cache)
        {
            return _fileReader.ReadByte(address);
        }

        public ItemData<float> ReadFloat(DeviceAddress address, DataSource source = DataSource.Cache)
        {
            return _fileReader.ReadFloat(address);
        }

        public ItemData<bool> ReadBool(DeviceAddress address, DataSource source = DataSource.Cache)
        {
            return _fileReader.ReadBit(address);
        }

        public ItemData<string> ReadString(DeviceAddress address, DataSource source = DataSource.Cache)
        {
            if (source == DataSource.Device) return _fileReader.ReadString(address, address.DataSize);
            else
            {
                StringTag tag = IOTagGroup[address.Name] as StringTag;
                return tag == null ? new ItemData<string>(null, 0, QUALITIES.NG) :
                    new ItemData<string>(tag.Value, 0, tag.Quality);
            }
        }

        public ItemData<dynamic> ReadDynamic(DeviceAddress address, DataSource source = DataSource.Cache)
        {
            throw new NotImplementedException();
        }

        public int WriteInt32(DeviceAddress address, int value)
        {
            int rs = _fileReader.WriteInt32(address, value);
            return rs;
        }

        public int WriteUInt32(DeviceAddress address, uint value)
        {
            int rs = _fileReader.WriteUInt32(address, value);
            return rs;
        }

        public int WriteUInt16(DeviceAddress address, ushort value)
        {
            int rs = _fileReader.WriteUInt16(address, value);
            return rs;
        }

        public int WriteInt16(DeviceAddress address, short value)
        {
            int rs = _fileReader.WriteInt16(address, value);
            return rs;
        }

        public int WriteFloat(DeviceAddress address, float value)
        {
            int rs = _fileReader.WriteFloat(address, value);
            return rs;
        }

        public int WriteString(DeviceAddress address, string value)
        {
            int rs = _fileReader.WriteString(address, value);

            return rs;
        }

        public int WriteBit(DeviceAddress address, bool value)
        {
            int rs = _fileReader.WriteBit(address, value);
            return rs;
        }

        public int WriteBits(DeviceAddress address, byte value)
        {
            int rs = _fileReader.WriteBits(address, value);
            return rs;
        }

        public override void Dispose()
        {
            _IOTagGroup = null;
            base.Dispose();
        }

        public int WriteDouble(DeviceAddress address, double value)
        {
            throw new NotImplementedException();
        }

        public int WriteLong(DeviceAddress address, long value)
        {
            throw new NotImplementedException();
        }

        public event DataChangeEventHandler DataChange;
    }
}